#!/usr/bin/env node
/**
 * 智能地理编码服务 - 结合BIM数据
 * 1. 使用高德地图获取小区基础位置
 * 2. 结合BIM数据中的建筑坐标进行精确定位
 */

const fs = require('fs').promises;
const path = require('path');
const axios = require('axios');
const XLSX = require('xlsx');

// 配置日志
class Logger {
    constructor() {
        this.logFile = 'geocoding_with_bim.log';
    }

    async log(level, message) {
        const timestamp = new Date().toISOString();
        const logMessage = `${timestamp} - ${level} - ${message}\n`;
        
        console.log(logMessage.trim());
        
        try {
            await fs.appendFile(this.logFile, logMessage, 'utf8');
        } catch (err) {
            console.error('写入日志文件失败:', err);
        }
    }

    info(message) {
        return this.log('INFO', message);
    }

    error(message) {
        return this.log('ERROR', message);
    }

    warning(message) {
        return this.log('WARNING', message);
    }
}

const logger = new Logger();

/**
 * 从common.js提取BIM数据
 */
class BIMDataExtractor {
    /**
     * 提取BIM建筑坐标数据
     */
    static async extractBimCoordinates() {
        const bimData = {};
        
        try {
            const content = await fs.readFile('common.js', 'utf8');
            
            // 提取queryBimData函数中的数据
            // 查找包含坐标的数据
            const pattern1 = /lng:([\d.]+),\s*lat:([\d.]+),.*?d:'([^']+)',.*?title:'([^']+)'/g;
            let match;
            
            while ((match = pattern1.exec(content)) !== null) {
                const [, lng, lat, dCode, title] = match;
                bimData[dCode] = {
                    longitude: parseFloat(lng),
                    latitude: parseFloat(lat),
                    title: title
                };
            }
            
            // 提取queryBuildingData函数中的详细房间数据
            const pattern2 = /"lat":([\d.]+),"lng":([\d.]+),.*?"id":"([^"]+)"/g;
            
            while ((match = pattern2.exec(content)) !== null) {
                const [, lat, lng, roomId] = match;
                bimData[roomId] = {
                    longitude: parseFloat(lng),
                    latitude: parseFloat(lat),
                    roomId: roomId
                };
            }
            
            await logger.info(`成功提取 ${Object.keys(bimData).length} 条BIM坐标数据`);
            return bimData;
            
        } catch (error) {
            await logger.error(`提取BIM数据失败: ${error.message}`);
            return {};
        }
    }
}

/**
 * 智能地理编码器 - 结合高德地图和BIM数据
 */
class SmartGeocoder {
    constructor(apiKey) {
        this.apiKey = apiKey;
        this.baseUrl = "https://restapi.amap.com/v3/geocode/geo";
        this.cache = new Map();
        this.bimData = {};
        this.initializeBimData();
    }

    async initializeBimData() {
        this.bimData = await BIMDataExtractor.extractBimCoordinates();
    }

    /**
     * 获取小区的基础坐标
     */
    async geocodeCommunity(communityName) {
        if (this.cache.has(communityName)) {
            return this.cache.get(communityName);
        }

        const params = {
            key: this.apiKey,
            address: communityName,
            output: 'json'
        };

        try {
            const response = await axios.get(this.baseUrl, { 
                params: params,
                timeout: 10000 
            });
            
            const data = response.data;
            
            if (data.status === '1' && data.count !== '0') {
                const geocode = data.geocodes[0];
                const location = geocode.location.split(',');
                
                const result = {
                    success: true,
                    longitude: parseFloat(location[0]),
                    latitude: parseFloat(location[1]),
                    formatted_address: geocode.formatted_address || '',
                    province: geocode.province || '',
                    city: geocode.city || '',
                    district: geocode.district || ''
                };
                
                this.cache.set(communityName, result);
                return result;
            } else {
                return { success: false };
            }
                
        } catch (error) {
            await logger.error(`地理编码失败: ${error.message}`);
            return { success: false };
        }
    }

    /**
     * 根据建筑编号获取精确坐标
     */
    getBuildingCoordinates(buildingNumber, roomNumber = null) {
        // 1. 首先尝试精确匹配房间ID
        if (roomNumber) {
            // 构建可能的房间ID格式
            const possibleIds = [
                `兴海嘉苑-${buildingNumber}-${roomNumber}`,
                `安滨嘉苑-${buildingNumber}-${roomNumber}`,
                `${buildingNumber}-${roomNumber}`
            ];
            
            for (const roomId of possibleIds) {
                if (this.bimData[roomId]) {
                    return this.bimData[roomId];
                }
            }
        }

        // 2. 尝试匹配建筑编号
        if (this.bimData[buildingNumber]) {
            return this.bimData[buildingNumber];
        }

        // 3. 尝试模糊匹配
        for (const [key, data] of Object.entries(this.bimData)) {
            if (key.includes(buildingNumber)) {
                return data;
            }
        }

        return null;
    }

    /**
     * 计算建筑物相对于小区中心的偏移量
     */
    calculateOffset(baseLat, baseLng, buildingNumber, index) {
        // 根据建筑编号计算偏移
        // 这是一个简单的算法，实际应用中可能需要更复杂的布局算法
        
        // 提取建筑编号中的数字
        const match = buildingNumber.match(/(\d+)/);
        const buildingNum = match ? parseInt(match[1]) : index;
        
        // 计算行列位置（假设建筑按网格排列）
        const row = Math.floor((buildingNum - 1) / 10);
        const col = (buildingNum - 1) % 10;
        
        // 每栋楼之间的间距（经纬度）
        const spacingLat = 0.0002;  // 约22米
        const spacingLng = 0.0003;  // 约30米
        
        // 计算偏移后的坐标
        const offsetLat = baseLat + (row - 5) * spacingLat;
        const offsetLng = baseLng + (col - 5) * spacingLng;
        
        return [offsetLat, offsetLng];
    }
}

/**
 * 处理房产数据 - 结合BIM坐标
 */
async function processHouseDataWithBim(apiKey) {
    await logger.info("开始处理房产权属数据（结合BIM数据）...");
    
    // 读取Excel文件
    let workbook, worksheet, jsonData;
    
    try {
        workbook = XLSX.readFile('house_owner.xls');
        const sheetName = workbook.SheetNames[0];
        worksheet = workbook.Sheets[sheetName];
        jsonData = XLSX.utils.sheet_to_json(worksheet);
        
        await logger.info(`成功读取 ${jsonData.length} 条记录`);
        await logger.info(`列名: ${Object.keys(jsonData[0] || {}).join(', ')}`);
        
    } catch (error) {
        await logger.error(`读取Excel文件失败: ${error.message}`);
        return;
    }

    // 创建智能地理编码器
    const geocoder = new SmartGeocoder(apiKey);
    await geocoder.initializeBimData();

    // 初始化结果列
    jsonData.forEach(row => {
        row.longitude = null;
        row.latitude = null;
        row.geocode_method = '';  // 记录获取坐标的方法
        row.geocode_confidence = 0.0;
        row.formatted_address = '';
        row.province = '';
        row.city = '';
        row.district = '';
    });

    // 统计
    const stats = {
        bim_exact: 0,  // BIM精确匹配
        bim_building: 0,  // BIM建筑匹配
        calculated: 0,  // 计算得出
        community_center: 0,  // 小区中心点
        failed: 0  // 失败
    };

    // 获取小区基础坐标
    let communityResult = null;
    if (jsonData.length > 0 && jsonData[0].xqname) {
        const xqname = jsonData[0].xqname;
        if (xqname) {
            await logger.info(`获取小区 '${xqname}' 的基础坐标...`);
            communityResult = await geocoder.geocodeCommunity(String(xqname));
            if (communityResult.success) {
                await logger.info(`小区中心坐标: (${communityResult.longitude}, ${communityResult.latitude})`);
            }
        }
    }

    // 处理每条记录
    for (let index = 0; index < jsonData.length; index++) {
        const row = jsonData[index];
        await logger.info(`\n处理 [${index + 1}/${jsonData.length}]:`);
        
        const buildingNumber = String(row.building_number || '').trim();
        const roomNumber = String(row.room_number || '').trim();
        
        // 1. 尝试从BIM数据获取精确坐标
        const bimCoords = geocoder.getBuildingCoordinates(buildingNumber, roomNumber);
        
        if (bimCoords) {
            row.longitude = bimCoords.longitude;
            row.latitude = bimCoords.latitude;
            row.geocode_method = roomNumber ? 'BIM精确匹配' : 'BIM建筑匹配';
            row.geocode_confidence = roomNumber ? 1.0 : 0.9;
            
            if (roomNumber) {
                stats.bim_exact++;
            } else {
                stats.bim_building++;
            }
            
            await logger.info(`  ${buildingNumber} ${roomNumber} -> BIM坐标: (${bimCoords.longitude}, ${bimCoords.latitude})`);
            
        // 2. 如果没有BIM数据，使用小区中心点+偏移计算
        } else if (communityResult && communityResult.success && buildingNumber) {
            const [offsetLat, offsetLng] = geocoder.calculateOffset(
                communityResult.latitude,
                communityResult.longitude,
                buildingNumber,
                index
            );
            
            row.longitude = offsetLng;
            row.latitude = offsetLat;
            row.geocode_method = '基于小区中心计算';
            row.geocode_confidence = 0.7;
            stats.calculated++;
            
            await logger.info(`  ${buildingNumber} -> 计算坐标: (${offsetLng}, ${offsetLat})`);
            
        // 3. 使用小区中心点
        } else if (communityResult && communityResult.success) {
            row.longitude = communityResult.longitude;
            row.latitude = communityResult.latitude;
            row.geocode_method = '小区中心点';
            row.geocode_confidence = 0.5;
            stats.community_center++;
            
            await logger.info(`  使用小区中心点: (${communityResult.longitude}, ${communityResult.latitude})`);
            
        } else {
            row.geocode_method = '失败';
            row.geocode_confidence = 0.0;
            stats.failed++;
            await logger.warning(`  无法获取坐标`);
        }
        
        // 填充地址信息
        if (communityResult && communityResult.success) {
            row.formatted_address = communityResult.formatted_address || '';
            row.province = communityResult.province || '';
            row.city = communityResult.city || '';
            row.district = communityResult.district || '';
        }
    }

    // 保存结果
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
    const outputFile = `house_owner_geocoded_bim_${timestamp}.xlsx`;
    
    const newWorkbook = XLSX.utils.book_new();
    const newWorksheet = XLSX.utils.json_to_sheet(jsonData);
    XLSX.utils.book_append_sheet(newWorkbook, newWorksheet, 'Sheet1');
    XLSX.writeFile(newWorkbook, outputFile);
    
    await logger.info(`\n结果已保存到: ${outputFile}`);
    
    // 生成详细报告
    const report = `
地理编码完成报告（结合BIM数据）
================================
处理时间: ${new Date().toLocaleString()}
总记录数: ${jsonData.length}

坐标获取方式统计:
  BIM精确匹配: ${stats.bim_exact} 条
  BIM建筑匹配: ${stats.bim_building} 条
  基于小区计算: ${stats.calculated} 条
  小区中心点: ${stats.community_center} 条
  失败: ${stats.failed} 条

成功率: ${((jsonData.length - stats.failed) / jsonData.length * 100).toFixed(2)}%
`;

    // 添加坐标范围统计
    const validData = jsonData.filter(row => row.longitude !== null);
    if (validData.length > 0) {
        const longitudes = validData.map(row => row.longitude);
        const latitudes = validData.map(row => row.latitude);
        const lonRange = [Math.min(...longitudes), Math.max(...longitudes)];
        const latRange = [Math.min(...latitudes), Math.max(...latitudes)];
        
        const additionalReport = `
坐标范围:
  经度: ${lonRange[0].toFixed(6)} ~ ${lonRange[1].toFixed(6)}
  纬度: ${latRange[0].toFixed(6)} ~ ${latRange[1].toFixed(6)}
  
坐标分布:
  不同经度值: ${new Set(longitudes).size} 个
  不同纬度值: ${new Set(latitudes).size} 个
`;

        const finalReport = report + additionalReport;
        
        // 保存报告
        const reportFile = `house_owner_geocoded_bim_${timestamp}_report.txt`;
        await fs.writeFile(reportFile, finalReport, 'utf8');
        
        await logger.info(`报告已保存到: ${reportFile}`);
        await logger.info("\n" + finalReport);
        
        // 显示部分结果示例
        await logger.info("\n结果示例（前10条不同坐标）:");
        const uniqueCoords = new Map();
        const sampleData = [];
        
        for (const row of validData) {
            const key = `${row.longitude},${row.latitude}`;
            if (!uniqueCoords.has(key) && sampleData.length < 10) {
                uniqueCoords.set(key, true);
                sampleData.push(row);
            }
        }
        
        for (const row of sampleData) {
            await logger.info(`  ${row.building_number || ''} ${row.room_number || ''} -> ` +
                           `(${row.longitude.toFixed(6)}, ${row.latitude.toFixed(6)}) - ${row.geocode_method}`);
        }
    }
}

/**
 * 主函数
 */
async function main() {
    const API_KEY = "64fdb23b96e7a2c0c94c95a789ecef50";
    
    await logger.info("=" * 60);
    await logger.info("智能地理编码服务 - 结合BIM数据");
    await logger.info("=" * 60);
    
    // 检查必要文件
    try {
        await fs.access('house_owner.xls');
    } catch (error) {
        await logger.error("找不到 house_owner.xls 文件！");
        return;
    }
    
    try {
        await fs.access('common.js');
    } catch (error) {
        await logger.error("找不到 common.js 文件！");
        return;
    }
    
    // 处理数据
    await processHouseDataWithBim(API_KEY);
}

// 运行主函数
if (require.main === module) {
    main().catch(error => {
        console.error('程序执行出错:', error);
        process.exit(1);
    });
}

module.exports = {
    BIMDataExtractor,
    SmartGeocoder,
    processHouseDataWithBim
};